package com.sunchen.asc.service.user.server;

import com.alibaba.fastjson.JSONObject;
import com.sunchen.asc.service.common.ResultResponse;
import com.sunchen.asc.service.common.ResultUtil;
import com.sunchen.asc.service.user.api.RoleService;
import com.sunchen.asc.service.user.domain.Authentication;
import com.sunchen.asc.service.user.domain.Resource;
import com.sunchen.asc.service.user.domain.Role;
import com.sunchen.asc.service.user.dto.RoleDto;
import com.sunchen.asc.service.user.repository.AuthenticationRepository;
import com.sunchen.asc.service.user.repository.ResourceRepository;
import com.sunchen.asc.service.user.repository.RoleRepository;
import com.sunchen.asc.service.user.repository.UserRepository;
import com.sunchen.asc.service.user.vo.AuthVo;
import com.sunchen.asc.service.user.vo.ResourceVo;
import com.sunchen.asc.service.user.vo.RoleDetailVo;
import com.sunchen.asc.service.user.vo.RoleVo;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;

import javax.transaction.Transactional;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@DubboService(retries = 0)
public class RoleServiceImpl implements RoleService {

    @Autowired
    RoleRepository roleRepository;
    @Autowired
    AuthenticationRepository authenticationRepository;
    @Autowired
    UserRepository userRepository;
    @Autowired
    ResourceRepository resourceRepository;
    @Autowired
    ResourceServiceImpl resourceService;

    public ResultResponse getAuthentication() {

        List<AuthVo> vos = authenticationRepository.findVo();
        return ResultUtil.success(vos);
    }

    @Transactional
    public Page<RoleVo> roleList(Pageable pageable,String name) {

        Page<Role> roles = roleRepository.findByNameLikeAndDeleteFlag("%"+name+"%",0,pageable);
        List<RoleVo> vos = roles.getContent().stream().map(p ->{
            RoleVo vo = new RoleVo();
            vo.setId(p.getId().toString());
            vo.setName(p.getName());
            vo.setStatus(p.getStatus());
            vo.setTitle(p.getTitle());
            vo.setDescription(p.getDescription());
            vo.setAuthString(p.getAuthentications().parallelStream().map(Authentication::getName).collect(Collectors.joining(",")));
            vo.setResourceIds(p.getResources().stream().map(Resource::getId).collect(Collectors.toList()));
            return vo;
        }).collect(Collectors.toList());

        return new PageImpl<>(vos,roles.getPageable(),roles.getTotalElements());
    }

    public ResultResponse getRoleDetail(Long id) {

        Role role = roleRepository.getOne(id);
        RoleDetailVo roleDetailVo = new RoleDetailVo();
        roleDetailVo.setId(role.getId().toString());
        roleDetailVo.setName(role.getName());
        roleDetailVo.setStatus(role.getStatus());
        roleDetailVo.setTitle(role.getTitle());
        roleDetailVo.setDescription(role.getDescription());
        roleDetailVo.setAuthVos(role.getAuthentications().stream().map(authentication -> {
            AuthVo authVo = new AuthVo();
            authVo.setId(authentication.getId().toString());
            authVo.setName(authentication.getName());
            authVo.setTitle(authentication.getTitle());
            return authVo;
        }).collect(Collectors.toList()));
        roleDetailVo.setUrlIds(role.getResources().stream().map(Resource::getId).collect(Collectors.toList()));

        return ResultUtil.success(roleDetailVo);
    }

    public ResultResponse addRoleUrl(Long id, List<Long> urlIds) {

        Role role = roleRepository.getOne(id);
        List<Resource> resources = new ArrayList<>();
        for (Long urlId:urlIds){
            Resource resource = new Resource();
            resource.setId(urlId);
            resources.add(resource);
        }
        role.setResources(resources);
        roleRepository.save(role);
        List<Role> roles = roleRepository.findAll();
        //更新redis
        resourceService.resourceRoleSync(roles);
        return ResultUtil.success("成功");
    }

    public ResultResponse getRoles() {

        List<RoleVo> roles = roleRepository.findVoByStatusAndDeleteFlag(1,0);
        return ResultUtil.success(roles);
    }

    public ResultResponse authList(Pageable pageable, String title) {

        Page<Authentication> result = authenticationRepository.findByTitleLike(pageable,"%"+title+"%");
        List<AuthVo> vos = result.getContent().stream().map( authentication -> {
            AuthVo vo = new AuthVo(authentication.getId(),authentication.getName(),authentication.getTitle());
            return vo;
        }).collect(Collectors.toList());
        Page<AuthVo> authVoPage = new PageImpl<>(vos,result.getPageable(),result.getTotalElements());
        return ResultUtil.success(authVoPage);
    }

    public ResultResponse urlList() {

        List<ResourceVo> vos = resourceRepository.findVo();
        return ResultUtil.success(vos);
    }

    public ResultResponse getRoleByUrl(Long id) {

        List<Role> roles = roleRepository.getRoleByUrlId(id);
        List<RoleVo> vos = roles.stream().map(role -> {
            RoleVo vo = new RoleVo(role.getId(),role.getName(),role.getStatus(),role.getTitle(),role.getDescription());
            return vo;
        }).collect(Collectors.toList());
        return ResultUtil.success(vos);
    }

    public ResultResponse urlQuery(String title,Pageable pageable) {

        Page<Resource> resources = resourceRepository.findByTitleLike("%"+title+"%",pageable);
        List<ResourceVo> vos = resources.getContent().stream().map(resource -> {
            ResourceVo vo = new ResourceVo(resource.getId(),resource.getUrl(),resource.getTitle());
            return vo;
        }).collect(Collectors.toList());
        Page<ResourceVo> result = new PageImpl<>(vos,resources.getPageable(),resources.getTotalElements());
        return ResultUtil.success(result);
    }

    public ResultResponse resourceUpdate() {

        List<Role> roles = roleRepository.findAll();
        resourceService.resourceRoleSync(roles);
        return ResultUtil.success("1");
    }

    public ResultResponse creatAuthentication(String name, String title) {

        Long count = authenticationRepository.countByName(name);
        if (count > 0){
            return ResultUtil.failed("该权限已存在");
        }
        Authentication authentication = new Authentication();
        authentication.setName(name);
        authentication.setTitle(title);

        authenticationRepository.save(authentication);
        return ResultUtil.success("创建成功");
    }

    public ResultResponse editAuthentication(Long id, String name, String title) {

        Authentication authentication = authenticationRepository.getOne(id);
        if (!authentication.getName().equals(name)){
            Long count = authenticationRepository.countByName(name);
            if (count > 0){
                return ResultUtil.failed("该权限已存在");
            }
        }
        authentication.setTitle(title);
        authentication.setName(name);
        authenticationRepository.save(authentication);
        return ResultUtil.success("修改成功");
    }

    public ResultResponse deleteAuthentication(Long id) {

        List<Long> roleIds = authenticationRepository.findRoles(id);
        if (roleIds.size() > 0){
            List<String> roleNames = roleRepository.findNameInIds(roleIds);
            if (roleNames.size() > 0){
                ResultResponse res = ResultUtil.failed("该权限存在使用角色，无法删除");
                res.setData(roleNames);
                return res;
            }
        }
        authenticationRepository.deleteById(id);
        return ResultUtil.success("删除成功");
    }

    public ResultResponse creatRole(RoleDto roleDto) {

        if (!roleDto.getName().startsWith("ROLE_")){
            return ResultUtil.failed("角色名要求ROLE_开头");
        }

        Long count = roleRepository.countByNameAndDeleteFlag(roleDto.getName(),0);
        if (count>0){
            return ResultUtil.failed("该角色已存在");
        }
        Role role = new Role();
        role.setName(roleDto.getName());
        role.setStatus(roleDto.getStatus());
        role.setDeleteFlag(0);
        role.setStatus(1);
        role.setTitle(roleDto.getTitle());
        role.setDescription(roleDto.getDescription());
        //role.setCreateUser();
        List<Authentication> authentications = new ArrayList<>();
        for (Long id:roleDto.getAuthenticationIds()){
            Authentication authentication = new Authentication();
            authentication.setId(id);
            authentications.add(authentication);
        }
        role.setAuthentications(authentications);
        roleRepository.save(role);

        return ResultUtil.success("创建成功");
    }

    public ResultResponse editRole(RoleDto roleDto) {

        if (!roleDto.getName().startsWith("ROLE_")){
            return ResultUtil.failed("角色名要求ROLE_开头");
        }
        Role oldRole = roleRepository.getOne(roleDto.getId());
        if (!oldRole.getName().equals(roleDto.getName())){
            Long count = roleRepository.countByNameAndDeleteFlag(roleDto.getName(),0);
            if (count>0){
                return ResultUtil.failed("该角色已存在");
            }
        }
        oldRole.setName(roleDto.getName());
        oldRole.setTitle(roleDto.getTitle());
        oldRole.setDescription(roleDto.getDescription());
        //oldRole.setUpdateUser();
        List<Authentication> authentications = new ArrayList<>();
        for (Long id:roleDto.getAuthenticationIds()){
            Authentication authentication = new Authentication();
            authentication.setId(id);
            authentications.add(authentication);
        }
        oldRole.setAuthentications(authentications);
        roleRepository.save(oldRole);
        return ResultUtil.success("修改成功");
    }

    public ResultResponse deleteRole(Long id) {

        List<Long> userIds = roleRepository.findUsers(id);
        if (userIds.size() > 0){
            List<String> names = userRepository.findNameInIds(userIds);
            if (names.size() > 0){
                ResultResponse res = ResultUtil.failed("该角色存在使用用户，无法删除");
                res.setData(names);
                return res;
            }
        }
        Role role = roleRepository.getOne(id);
        role.setDeleteFlag(1);
        role.setDeleteTime(new Timestamp(System.currentTimeMillis()));
        List<Resource> resources = new ArrayList<>();
        role.setResources(resources);
        List<Authentication> authentications = new ArrayList<>();
        role.setAuthentications(authentications);
        //role.setDeleteUser();
        roleRepository.save(role);

        return ResultUtil.success("删除成功");
    }

    public ResultResponse setStatus(Long id, int status) {

        Role role = roleRepository.getOne(id);
        role.setStatus(status);
        //role.setUpdateUser();
        roleRepository.save(role);
        return ResultUtil.success("修改成功");
    }

    public JSONObject findTheOnlyNameCreat(String name) {
        JSONObject res = new JSONObject();
        Role role = roleRepository.findFirstByNameAndDeleteFlag(name,0);
        if(null != role){
            res.put("valid",false);
            res.put("message","已存在");
        }else{
            res.put("valid",true);
            res.put("message","可用");
        }
        return res;
    }

    public JSONObject findTheOnlyNameModify(String name, Long id) {
        JSONObject res = new JSONObject();
        String oldName = roleRepository.findNameById(id);
        if (oldName.equals(name)){
            res.put("valid",true);
            res.put("message","可用");
            return res;
        }
        Role role = roleRepository.findFirstByNameAndDeleteFlag(name,0);
        if(null != role){
            res.put("valid",false);
            res.put("message","已存在");
        }else{
            res.put("valid",true);
            res.put("message","可用");
        }
        return res;
    }

    public JSONObject findTheOnlyAuthNameCreat(String name) {
        JSONObject res = new JSONObject();
        Authentication authentication = authenticationRepository.findFirstByName(name);
        if(null != authentication){
            res.put("valid",false);
            res.put("message","已存在");
        }else{
            res.put("valid",true);
            res.put("message","可用");
        }
        return res;
    }

    public JSONObject findTheOnlyAuthNameModify(String name, Long id) {
        JSONObject res = new JSONObject();
        String oldName = authenticationRepository.findNameById(id);
        if (oldName.equals(name)){
            res.put("valid",true);
            res.put("message","可用");
            return res;
        }
        Authentication authentication = authenticationRepository.findFirstByName(name);
        if(null != authentication){
            res.put("valid",false);
            res.put("message","已存在");
        }else{
            res.put("valid",true);
            res.put("message","可用");
        }
        return res;
    }
}
